﻿using System.Diagnostics;
using System.Linq.Expressions;

namespace WenAntdUI.Helps
{
    public static class ListTreeHelp
    {
        /// <summary>
        /// List<typeparamref name="T"/> 转换成树结构
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <typeparam name="TChild"></typeparam>
        /// <param name="items"></param>
        /// <param name="idSelector"></param>
        /// <param name="parentIdSelector"></param>
        /// <param name="children"></param>
        /// <returns></returns>
        public static List<T> ConvertToTree<T, TKey, TChild>(this List<T> items,
            Func<T, TKey> idSelector,
            Func<T, TKey> parentIdSelector,
            Expression<Func<T, TChild>> children) where T : class where TKey : class where TChild : class
        {
            var tns = items.ConvertToTree(idSelector, parentIdSelector);

            List<T> getItems(List<TreeNode<TKey, T>> items)
            {
                var lis = new List<T>();
                foreach (var item in items)
                {
                    var it = item.Data;
                    lis.Add(it);
                    if (item.Children.Count > 0)
                    {
                        var subs = getItems(item.Children);
                        if (subs.Count > 0)
                        {
                            if (children.Compile().Invoke(it) is List<T> s)
                            {
                                s.Clear();
                                s.AddRange(subs);
                            }
                            else if (children.Body is MemberExpression member)
                            {
                                it.GetType().GetProperty(member.Member.Name)?.SetValue(it, subs);
                            }
                        }
                    }
                }
                return lis;
            }
            return getItems(tns);
        }

        /// <summary>
        /// 将平面列表转换为树形结构
        /// </summary>
        /// <param name="items">数据源</param>
        /// <param name="idSelector">节点唯一标识字段</param>
        /// <param name="parentIdSelector">父节点标识字段</param>
        public static List<TreeNode<TKey, T>> ConvertToTree<T, TKey>(
            this List<T> items,
            Func<T, TKey> idSelector,
            Func<T, TKey> parentIdSelector) where T : class where TKey : class
        {
            var dict = items.ToDictionary(
                idSelector,
                item => new TreeNode<TKey, T>
                {
                    Id = idSelector(item),
                    ParentId = parentIdSelector(item),
                    Data = item
                });

            List<TreeNode<TKey, T>> rootNodes = new List<TreeNode<TKey, T>>();
            var processedIds = new HashSet<TKey>();
            foreach (var node in dict.Values)
            {
                // 循环引用检测
                if (processedIds.Contains(node.Id))
                    throw new InvalidOperationException($"循环引用: ID={node.Id}");
                processedIds.Add(node.Id);

                // 自动根节点判断逻辑
                if (node.ParentId is null ||
                    !dict.ContainsKey(node.ParentId) ||
                    EqualityComparer<TKey>.Default.Equals(node.ParentId, node.Id))
                {
                    rootNodes.Add(node);
                    continue;
                }


                // 挂载到父节点
                if (dict.TryGetValue(node.ParentId, out var parent))
                {
                    parent.Children.Add(node);
                }
                else
                {
                    // 处理孤儿节点策略
                    Debug.WriteLine($"未连接节点: ID={node.Id} → ParentID={node.ParentId}");
                    rootNodes.Add(node);  // 自动挂载到根节点
                }
            }
            return rootNodes;
        }
        public class TreeNode<TKey, T> where T : class where TKey : class
        {
            public T Data { get; set; }
            public TKey Id { get; set; }
            public TKey ParentId { get; set; }
            public List<TreeNode<TKey, T>> Children { get; set; } = [];
        }
    }
}
